package org.bjf.modules.process.service;

import static org.bjf.modules.process.constants.ProcessConstant.AUDITOR_LIST;
import static org.bjf.modules.process.constants.ProcessConstant.BIZ_INFO;
import static org.bjf.modules.process.constants.ProcessConstant.USER_AUDIT_INFO;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bjf.exception.ServiceException;
import org.bjf.modules.process.bean.AuditTask;
import org.bjf.modules.process.bean.ProcessAudit;
import org.bjf.modules.process.bean.ProcessInfo;
import org.bjf.modules.process.bean.UserAuditInfo;
import org.bjf.modules.sys.bean.SysUser;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * @author bjf
 * @date 2017/11/27
 */
@Service
@Slf4j
public class StandardFlowService {

  @Autowired
  private RuntimeService runtimeService;
  @Autowired
  private TaskService taskService;
  @Autowired
  private IdentityService identityService;

  @Autowired
  private ProcessInfoService processInfoService;
  @Autowired
  private ProcessAuditService processAuditService;


  /**
   * 启动流程
   *
   * @param processInfo 流程信息
   * @param auditors 审批人列表
   * @return 流程实例ID
   */
  public String startProcess(ProcessInfo processInfo, List<SysUser> auditors) {

    if (processInfo == null || processInfo.getBizType() == null || StringUtils
        .isBlank(processInfo.getBizKey())) {
      throw new ServiceException("业务信息不能为空");
    }
    if (CollectionUtils.isEmpty(auditors)) {
      throw new ServiceException("审批人不能为空");
    }

    HashMap<String, Object> vars = new HashMap<>(2);
    vars.put(BIZ_INFO, JSON.toJSONString(processInfo));
    vars.put(AUDITOR_LIST, JSON.toJSONString(auditors));

    String defKey = "standardProcess";
    // 设置发起人
    identityService.setAuthenticatedUserId(processInfo.getUserId() + "");
    ProcessInstance pi = runtimeService
        .startProcessInstanceByKey(defKey, processInfo.getBizKey(), vars);

    //====记录流程信息
    processInfo.setPiId(pi.getId());
    processInfoService.add(processInfo);

    return pi.getId();
  }

  /**
   * 待办列表
   */
  public List<AuditTask> listTask(Long userId) {
    //===1.查出用户的流程列表
    List<Task> tasks = taskService.createTaskQuery().
        or().
        taskAssignee(String.valueOf(userId))
        .taskCandidateUser(String.valueOf(userId))
        .endOr()
        .orderByTaskCreateTime().desc()
        .list();
    if (tasks.isEmpty()) {
      return Collections.emptyList();
    }

    LambdaQueryWrapper<ProcessAudit> qw = new LambdaQueryWrapper<>();
    qw.in(ProcessAudit::getTaskId, tasks.stream().map(Task::getId).collect(Collectors.toList()));
    List<ProcessAudit> processAudits = processAuditService.listAll(qw);

    List<AuditTask> list = new ArrayList<>(processAudits.size());
    for (ProcessAudit processAudit : processAudits) {
      AuditTask at = new AuditTask();
      BeanUtils.copyProperties(processAudit, at);
      at.setProcessInfo(processInfoService
          .getOne(new LambdaQueryWrapper<ProcessInfo>()
              .eq(ProcessInfo::getPiId, processAudit.getPiId())));

      list.add(at);
    }

    return list;
  }


  /**
   * 审批
   *
   * @param taskId 任务ID
   * @param userAuditInfo 审批信息
   */
  public void submitTask(String taskId, UserAuditInfo userAuditInfo) {

    //查询当前审批节点
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
      throw new ServiceException("流程任务不存在");
    }

    Map<String, Object> vars = new HashMap<>(2);
    vars.put(USER_AUDIT_INFO, JSON.toJSONString(userAuditInfo));
    //完成审批任务
    taskService.complete(task.getId(), vars);

  }
}
